
package com.niudong.esdemo.pscsoft;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.profile.ProfileShardResult;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.SuggestionBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestion;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class QueryByRegexp {
    public static void main(String[] args) {
        initEs();

        SearchRequest player = buildSearchRequestRegexp("mycopyto");
        executeSearchRequest(player);
        closeEs();
    }

    private static RestHighLevelClient restClient;
    private static Log log = LogFactory.getLog(QueryByRegexp.class);
    // 初始化连接


    public static void initEs() {
        restClient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

        log.info("ElasticSearch init in service.");
    }

    // 关闭连接
    public static void closeEs() {
        try {
            restClient.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static SearchRequest buildSearchRequestRegexp(String indices) {
        SearchRequest searchRequest = new SearchRequest();

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();


        searchSourceBuilder.query(QueryBuilders.regexpQuery("B","[0-9]*"));

        //searchSourceBuilder.query(QueryBuilders.scriptQuery(new Script("Integer.parseInt(doc['B'].value)")));



        searchRequest = new SearchRequest(indices);
        searchRequest.routing("routing");
        searchRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
        searchRequest.preference("_local");

        SumAggregationBuilder sum = AggregationBuilders.sum("sumB").field("B").script(new Script("Integer.parseInt(doc['B'].value)"));
        searchSourceBuilder.aggregation(sum);

        searchRequest.source(searchSourceBuilder);
        return searchRequest;
    }



    // 同步方式执行SearchRequest
    public static void executeSearchRequest(SearchRequest searchRequest) {

        // 运行
        try {
            SearchResponse searchResponse = restClient.search(searchRequest, RequestOptions.DEFAULT);
            log.info(searchResponse.toString());
            // 解析SearchResponse
            processSearchResponse(searchResponse);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭ES的连接
            closeEs();
        }
    }


    // 解析SearchResponse
    private static void processSearchResponse(SearchResponse searchResponse) {
        if (searchResponse == null) {
            return;
        }

        // 获取HTTP状态代码
        RestStatus status = searchResponse.status();
        // 获取请求执行时间
        TimeValue took = searchResponse.getTook();
        // 获取请求是否提前终止
        Boolean terminatedEarly = searchResponse.isTerminatedEarly();
        // 获取请求是否超时
        boolean timedOut = searchResponse.isTimedOut();
        log.info("status is " + status + ";took is " + took + ";terminatedEarly is " + terminatedEarly
                + ";timedOut is " + timedOut);

        // 查看搜索影响的分片总数
        int totalShards = searchResponse.getTotalShards();
        // 执行搜索成功的分片的统计信息
        int successfulShards = searchResponse.getSuccessfulShards();
        // 执行搜索失败的分片的统计信息
        int failedShards = searchResponse.getFailedShards();
        log.info("totalShards is " + totalShards + ";successfulShards is " + successfulShards
                + ";failedShards is " + failedShards);
        System.out.println("totalShards is " + totalShards + ";successfulShards is " + successfulShards
                + ";failedShards is " + failedShards);

        for (ShardSearchFailure failure : searchResponse.getShardFailures()) {
            log.info("fail is " + failure.toString());
            System.out.println("fail is " + failure.toString());
        }

        // 获取响应中包含的搜索结果
        SearchHits hits = searchResponse.getHits();
        // SearchHits提供有关所有结果的全局信息，如点击总数或最高分数：
        TotalHits totalHits = hits.getTotalHits();
        // 点击总数
        long numHits = totalHits.value;
        // 最高分数
        float maxScore = hits.getMaxScore();
        log.info("numHits is " + numHits + ";maxScore is " + maxScore);
        System.out.println("numHits is " + numHits + ";maxScore is " + maxScore);
        // 嵌套在searchhits中的是可以迭代的单个搜索结果
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            // SearchHit提供对基本信息的访问，如索引、文档ID和每次搜索的得分：
            String index = hit.getIndex();
            String id = hit.getId();
            float score = hit.getScore();


            System.out.println("docId is " + id + ";docIndex is " + index + ";docScore is " + score);
            log.info("docId is " + id + ";docIndex is " + index + ";docScore is " + score);

            // 以JSON字符串形式返回文档源
            String sourceAsString = hit.getSourceAsString();

            // 以键/值对的映射形式返回文档源
            //name=郭德纲, team=cav, position=sf, salary=3000, age=33
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            String A = (String) sourceAsMap.get("A");
            String B = (String) sourceAsMap.get("B");
            String C = (String) sourceAsMap.get("C");

            System.out.println(A + B + C );

            Map<String, Object> innerObject = (Map<String, Object>) sourceAsMap.get("innerObject");
            log.info("sourceAsString is " + sourceAsString + ";sourceAsMap size is " + sourceAsMap.size());
            System.out.println("sourceAsString is " + sourceAsString + ";sourceAsMap size is " + sourceAsMap.size());

/*            // 高亮显示
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlight = highlightFields.get("content");
            // 获取包含高亮显示的字段内容的一个或多个片段
            Text[] fragments = highlight.fragments();
            String fragmentString = fragments[0].string();
            log.info("fragmentString is " + fragmentString);*/

        }

        // 聚合搜索
        Aggregations aggregations = searchResponse.getAggregations();
        if (aggregations == null) {
            return;
        }
        // 按content聚合
        Terms byCompanyAggregation = aggregations.get("by_content");
        // 获取Elastic为关键词的buckets
        Terms.Bucket elasticBucket = byCompanyAggregation.getBucketByKey("Elastic");
        // 获取平均年龄的子聚合
        Sum sum = elasticBucket.getAggregations().get("sumB");
        double avg = sum.getValue();
        log.info("sum is " + avg);

        // Suggest搜索
        Suggest suggest = searchResponse.getSuggest();
        if (suggest == null) {
            return;
        }
        // 按content搜索Suggest
        TermSuggestion termSuggestion = suggest.getSuggestion("content");
        for (TermSuggestion.Entry entry : termSuggestion.getEntries()) {
            for (TermSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                log.info("suggestText is " + suggestText);
            }
        }

        // 搜索时分析结果
        Map<String, ProfileShardResult> profilingResults = searchResponse.getProfileResults();
        if (profilingResults == null) {
            return;
        }
        for (Map.Entry<String, ProfileShardResult> profilingResult : profilingResults.entrySet()) {
            String key = profilingResult.getKey();
            ProfileShardResult profileShardResult = profilingResult.getValue();
            log.info("key is " + key + ";profileShardResult is " + profileShardResult.toString());
        }
    }

}
